package com.chenqi.config;

import com.chenqi.authentication.code.ImageCodeValidateFilter;
import com.chenqi.properties.SecurityProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @description:  SpringSecurity配置类
 * @program: ardai-securtiy-parent
 * @author: ChenQi
 * @create: 2021-03-2021/3/17-08-13
 */
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 注入配置类，读取yml文件，初始内容
     */
    @Autowired
    private SecurityProperties securityProperties;

    /**
     * 注入动态数据的获取
     */
    @Autowired
    private UserDetailsService customUserDetailsService;

    /**
     * 注入自定义认证成功处理器
     */
    @Autowired
    private AuthenticationSuccessHandler customAuthenticationSuccessHandler;

    /**
     * 自定义认证失败处理器
     */
    @Autowired
    private AuthenticationFailureHandler customAuthenticationFailureHandler;

    /**
     * 注入自定义验证码过滤器
     */

    @Autowired
    private ImageCodeValidateFilter imageCodeValidateFilter;

    @Bean
    public PasswordEncoder getPasswordEncoder() {
        //PasswordEncoder是一个接口，官方推荐BCryptPasswordEncoder的实现
        //返回的密码是通过 原秘密+盐值的组合再进行加密得到的。
        //解密的时候 是通过 密码+盐值 的组合得到密码 看与数据库得密文是否一致，一致就通过
        return new BCryptPasswordEncoder();
    }

    /**
     * 认证管理
     * 1.认证信息(用户名，密码)
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //数据库存储的密码必须是加密后的，不能是明文。不然会报错 There is no passwordEncoder mapped...
//        String password = getPasswordEncoder().encode("123456");
////        auth.inMemoryAuthentication().withUser("chendake").password(password)
////                //权限标识(如果没有则运行时会报错)
////        .authorities("ADMIN");
        auth.userDetailsService(customUserDetailsService);
    }

    /**
     * 资源配置的权限拦截
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        http.httpBasic() //采用httpBase认证方式(有弹出框)
        //需要注意的是，表单验证通过以后，springSecurity会重定向到上一次的请求!!!
          http.addFilterBefore(imageCodeValidateFilter, UsernamePasswordAuthenticationFilter.class)
                  .formLogin() //采用表单登陆验证的方式(有表单)
                .loginPage(securityProperties.getAuthentication().getLoginPage())
                  //处理登陆的请求
                  .usernameParameter(securityProperties.getAuthentication().getUsernameParameter())
                  .passwordParameter(securityProperties.getAuthentication().getPasswordParameter())
                  .loginProcessingUrl(securityProperties.getAuthentication().getLoginProcessingUrl())
                  .successHandler(customAuthenticationSuccessHandler)
                  .failureHandler(customAuthenticationFailureHandler)
                  .and()  //认证请求,放行登陆界面
                .authorizeRequests().antMatchers(securityProperties.getAuthentication().getLoginPage()).permitAll()
                .anyRequest().authenticated(); //所有访问应用的http请求都需要认证才可以访问
    }

    /**
     * 一般用户过滤静态资源
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(securityProperties.getAuthentication().getStaticPath());
    }
}
